#include "BigNum.h"

BigNum::BigNum()
{
}

BigNum::BigNum(int num)
{
    *this = num;
}

BigNum::BigNum(const char* num)
{
    *this = num;
}

BigNum BigNum::operator=(int num)
{
    char s[256] = { 0 };  
    
    sprintf(s, "%d", num);  
    *this = s;

    return *this;  
}

BigNum BigNum::operator=(const char* num)
{
    int len = strlen(num);

    for(int i = 0; i < len; i++)
    {
        m_vNumber.push_back(num[len - i - 1] - '0');  
    }

    return *this;  
}

BigNum BigNum::operator+(const BigNum& num) const
{
    BigNum tmp;
    int    carry = 0;
    int    maxLen = max(size(), num.size());

    for(int i = 0; carry || i < maxLen; i++)
    {  
        int x = carry;  
        
        if(i < size()) 
        {
            x += get(i);  
        }

        if(i < num.size())
        {
            x += num.get(i);  
        }
        
        carry = x / 10;  

        tmp.m_vNumber.push_back(x % 10);  
    }  

    return tmp;  
}

BigNum BigNum::operator-(const BigNum& num) const
{
    BigNum tmp;
    int    carry = 0;

    for(int i = 0; i < size(); i++) {  
        int x = get(i) - carry;

        if(i < num.size()) 
        {
            x -= num.get(i);  
        }

        if(x >= 0) 
        {
            carry = 0;  
        }
        else 
        {  
            carry = 1;  
            x += 10;  
        }  
        tmp.m_vNumber.push_back(x);
    }

    tmp.rmLeadingZero();

    return tmp;
}

BigNum BigNum::operator*(const BigNum& num) const
{
    BigNum tmp;

    for(int i = 0; i < size(); i++)
    {
        for(int j = 0; j < num.size(); j++)
        {
            int k = get(i) * num.get(j);

            if (i + j + 1 > tmp.size())
            {
                tmp.m_vNumber.push_back(k);
            }
            else
            {
                tmp.m_vNumber[i + j] += k;
            }
        }
    }

    for(int i = 0; i < tmp.size() - 1; i++)
    {  
        tmp.m_vNumber[i+1] += tmp.m_vNumber[i] / 10;  
        tmp.m_vNumber[i] %= 10;  
    }  

    return tmp;
}

std::string BigNum::str() const
{
    string                      res = "";
    vector<int>::const_iterator it;

    for(it = m_vNumber.begin(); it != m_vNumber.end(); it++)
    {
        res = (char)(*it + '0') + res;  
    }

    return res; 
}

int BigNum::size() const
{
    return m_vNumber.size();
}

int BigNum::get(int index) const
{
    if (index >= m_vNumber.size())
    {
        throw new exception("range error");
    }

    return m_vNumber[index];
}

void BigNum::rmLeadingZero()
{
    vector<int>::const_iterator it;

    for (int i = size() - 1; i >= 0; i--)
    {
        if (get(i) == 0) 
        {
            m_vNumber.pop_back();
        }
        else
        {
            break;
        }
    }
}

istream& operator>>(istream &in, BigNum& num)
{
    string s;

    in >> s;
    num = s.c_str(); 

    return in;  
}

ostream& operator<<(ostream &out, const BigNum& num)
{
    out << num.str();

    return out;  
}
